# encoding=utf-8

import redis
from hashlib import md5
from pymongo import MongoClient
import time
import motor.motor_asyncio
import asyncio
class Mongotext:
    '''
    MongoDB库操作
    '''
    def __init__(self):
        '''
        连接数据库，绑定库，集合
        '''

        # client = MongoClient(host='192.168.40.1',port=27017)  #连接到MongoDB
        # self.client = MongoClient(['127.0.0.1:27017','127.0.0.1:27018','127.0.0.1:27019'])
        self.client = motor.motor_asyncio.AsyncIOMotorClient(['127.0.0.1:27017','127.0.0.1:27018','127.0.0.1:27019'])
        self.collection = self.client["dht0"]["dht_type0"]        #绑定到url_text"库 "url"集合

    async def insert(self,url):
        '''
        插入数据
        :return:
        '''


        try:
            print("准备存入mongo")
            await self.collection.insert_one(url)  #插入一条数据

        except:
            print("inset_ERROR")




class SimpleHash():
    '''
    哈希算法
    '''
    def __init__(self, cap, seed):
        self.cap = cap
        self.seed = seed

    def hash(self, value):
        ret = 0
        for i in range(len(value)):
            ret += self.seed * ret + ord(value[i])
        return (self.cap - 1) & ret


class BloomFilter():
    '''
    布隆过滤-Redis
    '''
    def __init__(self, host='localhost', port=6379, db=3, blockNum=1, key='bloom5'):
        """
        :param host: the host of Redis
        :param port: the port of Redis
        :param db: witch db in Redis
        :param blockNum: one blockNum for about 90,000,000; if you have more strings for filtering, increase it.
        :param key: the key's name in Redis
        """
        self.server = redis.Redis(host=host, port=port, db=db)

        # <<表示二进制向左移动位数，比如2<<2,2的二进制表示000010，向左移2位，就是001000，就是十进制的8
        self.bit_size = 1 << 31  # Redis的String类型最大容量为512M，现使用256M
        self.seeds = [5, 7, 11, 13, 31, 37,61]
        self.key = key
        self.blockNum = blockNum
        self.hashfunc = []
        for seed in self.seeds:
            self.hashfunc.append(SimpleHash(self.bit_size, seed))

    def isContains(self, str_input):
        '''
        判断是否在Redis中存在
        :param str_input:
        :return:
        '''
        if not str_input:
            return False
        m5 = md5()

        m5.update(str_input)
        str_input = m5.hexdigest()

        # print(str_input)

        ret = True
        name = self.key + str(int(str_input[0:2], 16) % self.blockNum)

        # print(name)

        for f in self.hashfunc:
            loc = f.hash(str_input)
            # print(loc)
            ret = ret & self.server.getbit(name, loc)
            # print(self.server.getbit(name, loc))

        return ret

    def insert(self, str_input):
        '''
        添加到Redis数据库

        :param str_input:
        :return:
        # '''
        m5 = md5()
        m5.update(str_input)
        str_input = m5.hexdigest()
        name = self.key + str(int(str_input[0:2], 16) % self.blockNum)  #int(str_input[0:2], 16)表示将16进制转成10进制

        for f in self.hashfunc:
            loc = f.hash(str_input)

            self.server.setbit(name, loc, 1)



if __name__ == '__main__':
    '''
    '''
    rediss = BloomFilter()
    mongs = Mongotext()
    print('-----------------开始-------------------------')
    # url = input('输入url:')
    for i in range(10000000):
        url = 'texn{}.com'.format(i)

        if rediss.isContains(url.encode()):
            # 判断字符串是否存在
            print('存在')

        else:
            print('不存在')
            loop = asyncio.get_event_loop()
            loop.run_until_complete(mongs.insert(url))
            # mongs.insert(url)
            rediss.insert(url.encode())

            print(url)




